package com.timk.goserver.client.ui.screens;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.TabPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.timk.goserver.client.model.ClientUserInfo;
import com.timk.goserver.client.model.GameInvite;
import com.timk.goserver.client.model.Message;
import com.timk.goserver.client.services.GameService;
import com.timk.goserver.client.services.GameServiceAsync;
import com.timk.goserver.client.services.MessageService;
import com.timk.goserver.client.services.MessageServiceAsync;
import com.timk.goserver.client.services.NoSessionException;
import com.timk.goserver.client.services.UserService;
import com.timk.goserver.client.services.UserServiceAsync;
import com.timk.goserver.client.ui.widgets.DisplayUserLinkListener;

/**
 * Main panel
 * @author TKington
 *
 */
public class MainPanel extends Composite {	// NOPMD - Complexity
	/** The MainPanel */
	public static MainPanel instance;	//	NOPMD - Possible unsafe assignment
	
	/**	User service endpoint */
	public static UserServiceAsync userService;
	/** Message service endpoint */
	public static MessageServiceAsync msgService;
	/** Game service endpoint */
	public static GameServiceAsync gameService;
	/** Logged in user */
	public static ClientUserInfo loggedInUser;	// NOPMD - Possible unsafe assignment
	
	final DockPanel dockPanel; // NOPMD - Explicit scoping
	StatusPanel statusPanel; // NOPMD - Explicit scoping
	final HTML userLabel; // NOPMD - Explicit scoping
	private final TabPanel tabPanel;
	private final List userList = new ArrayList();
	private static boolean expiredSession;	// NOPMD - Possible unsafe assignment
	
	/**
	 * Creates a MainPanel
	 *
	 */
	public MainPanel() {	// NOPMD - Complexity
		instance = this;
		
		bindServices();
		
		dockPanel = new DockPanel();
		dockPanel.setWidth("100%");
	    dockPanel.setStyleName("goserver-Main");
	    
	    HorizontalPanel topPanel = new HorizontalPanel();
	    topPanel.setWidth("100%");
	    dockPanel.add(topPanel, DockPanel.NORTH);
	    
	    HTML links = new HTML("<a href=\"Logout\">Log off</a>&nbsp;<a href=\"intro.html\">Info</a>");
	    topPanel.add(links);
	    
	    userLabel = new HTML();
	    topPanel.add(userLabel);
	    topPanel.setCellHorizontalAlignment(userLabel, HasHorizontalAlignment.ALIGN_RIGHT);

		VerticalPanel commandPanel = new VerticalPanel();
		commandPanel.setWidth("150px");
		dockPanel.add(commandPanel, DockPanel.WEST);
		
		Button userButton = new Button("Find User");
		userButton.addClickListener(new ClickListener() {
			public void onClick(Widget sender) {
				onFindUser();
			}
		});
		userButton.setWidth("100%");
		commandPanel.add(userButton);
		
		Button inviteButton = new Button("Invite");
		inviteButton.addClickListener(new ClickListener() {
			public void onClick(Widget sender) {
				onInvite();
			}
		});
		inviteButton.setWidth("100%");
		commandPanel.add(inviteButton);
		
		Button messageButton = new Button("Send Message");
		messageButton.addClickListener(new ClickListener() {
			public void onClick(Widget sender) {
				Message msg = new Message();
				msg.setFromUser(loggedInUser.getUsername());
				MessageDialog dlg = new MessageDialog(msg, true);
				dlg.show();
			}
		});
		messageButton.setWidth("100%");
		commandPanel.add(messageButton);
		
		Button profileButton = new Button("User Profile");
		profileButton.addClickListener(new ClickListener() {
			public void onClick(Widget sender) {
				UserProfileDialog dlg = new UserProfileDialog();
				dlg.show();
			}
		});
		profileButton.setWidth("100%");
		commandPanel.add(profileButton);
		
		Button changePassButton = new Button("Change Password");
		changePassButton.addClickListener(new ClickListener() {
			public void onClick(Widget sender) {
				ChangePasswordDialog dlg = new ChangePasswordDialog(MainPanel.this);
				dlg.show();
			}
		});
		changePassButton.setWidth("100%");
		commandPanel.add(changePassButton);
		
		tabPanel = new TabPanel();
		tabPanel.setWidth("100%");
		tabPanel.setHeight("100%");
		dockPanel.add(tabPanel, DockPanel.CENTER);
		dockPanel.setCellWidth(tabPanel, "100%");
		dockPanel.setCellHeight(tabPanel, "100%");
		
		dockPanel.setVisible(false);
		
		initWidget(dockPanel);
		
		expiredSession = false;
		userService.getCurrentUser(new AsyncCallback() {
			public void onSuccess(Object result) {
				if(result == null) {
					sessionExpired("Your session has expired.  Please log in.");
					return;
				}
				
				onGotUser((ClientUserInfo)result);
			}
			
			public void onFailure(Throwable caught) {
				if(caught instanceof NoSessionException) {
					MainPanel.sessionExpired(caught.getMessage());
					return;
				}
				
				Window.alert("Couldn't load user info");
				redirect("index.html");	
			}			
		});
	}
	
	void onGotUser(ClientUserInfo user) {
		loggedInUser = user;
		BoardPanel.setImageSize(user.getImageSize());

		statusPanel = new StatusPanel(this, user.getUsername());
		tabPanel.add(statusPanel, "Status");
		int newIndex = tabPanel.getWidgetCount() - 1;
		tabPanel.selectTab(newIndex);
		userList.add(loggedInUser.getUsername());
		
		dockPanel.setVisible(true);
		userLabel.setHTML("Logged in as: <b>" + loggedInUser.getUsername() + "</b>");

		Timer timer = new Timer() {
			public void run() {
				statusPanel.refresh();
			}
		};
		
		timer.scheduleRepeating(300000);
	}
	
	/**
	 * Sends a redirect
	 * @param url
	 */
	public static native void redirect (String url) /*-{
		$wnd.open (url, "_self", null);
	}-*/; 
	
	/**
	 * Called when session expires.
	 *
	 * @param msg the error message
	 */
	public static void sessionExpired(String msg) {
		if(!expiredSession) {
			expiredSession = true;
			Window.alert(msg);
			redirect("index.html");
		}
	}
	
	private void bindServices() {
		userService = (UserServiceAsync) GWT.create(UserService.class);
		ServiceDefTarget endpoint = (ServiceDefTarget)userService;
		String relativeURL = GWT.getModuleBaseURL() + "UserService";
		endpoint.setServiceEntryPoint(relativeURL);
		
		msgService = (MessageServiceAsync) GWT.create(MessageService.class);
		endpoint = (ServiceDefTarget)msgService;
		relativeURL = GWT.getModuleBaseURL() + "MessageService";
		endpoint.setServiceEntryPoint(relativeURL);
		
		gameService = (GameServiceAsync) GWT.create(GameService.class);
		endpoint = (ServiceDefTarget)gameService;
		relativeURL = GWT.getModuleBaseURL() + "GameService";
		endpoint.setServiceEntryPoint(relativeURL);
	}
	
	void onInvite() {
		GameInvite invite = new GameInvite();
		ArrayList players = new ArrayList();
		players.add(loggedInUser.getUsername());
		invite.setPlayers(players);
		
		InviteDialog dlg = new InviteDialog(statusPanel, invite, true);
		dlg.show();
	}
	
	void onFindUser() {
		DisplayUserLinkListener listener = new DisplayUserLinkListener(this);
		UserListDialog dlg = new UserListDialog(listener);
		dlg.show();
	}
	
	/**
	 * Shows a user's info on a new tab
	 * @param username the username
	 */
	public void showUser(String username) {
		int index = userList.indexOf(username);
		if(index != -1) {
			tabPanel.selectTab(index);
			return;
		}
		
		ViewUserPanel panel = new ViewUserPanel(this, username);
		tabPanel.add(panel, username);
		int newIndex = tabPanel.getWidgetCount() - 1;
		tabPanel.selectTab(newIndex);
		userList.add(username);
	}
	
	/**
	 * Removes the tab displaying the user's details
	 * @param username the username
	 */
	public void hideUser(String username) {
		int index = userList.indexOf(username);
		if(index != -1) {
			tabPanel.remove(index);
			userList.remove(index);
			tabPanel.selectTab(0);
		}
	}
}
